#include "bass.h"
#include "bass_ape.h"
#include "adaptors.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "pl_consts.h"


#ifndef _WIN32
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <unistd.h>
#endif


using namespace std;
bool engine_init()
{
    pl_consts_init();
    int res =  BASS_Init(-1, 44100, 0, 0, NULL);
    engine_load_all_plugins();
    return res;
}

void engine_free_allplugins()
{
    BASS_PluginFree(0);
}

void engine_free()
{
    engine_free_allplugins();
    BASS_Free();
}

void engine_set_attribute(HSTREAM hndl, DWORD params, float value)
{
    BASS_ChannelSetAttribute(hndl, params, value);
}

void engine_set_volume(HSTREAM hndl, float volume)
{
    BASS_SetVolume(volume);
}

void engine_channel_getdata(HSTREAM hndl, void* target, DWORD len)
{
    BASS_ChannelGetData(hndl, target, len);
}


QWORD engine_channel_getposition(HSTREAM hndl, DWORD mode)
{
    return BASS_ChannelGetPosition(hndl, mode);
}

void engine_channel_play(HSTREAM hndl, bool replay)
{
    BASS_ChannelPlay(hndl, replay);
}

void engine_channel_pause(HSTREAM hndl)
{
    BASS_ChannelPause(hndl);
}

void engine_channel_setposition(HSTREAM hndl, QWORD pos, QWORD mode)
{
    BASS_ChannelSetPosition(hndl, pos, mode);
}

void engine_channel_terminate(HSTREAM hndl)
{
    if (hndl == 0)
        return;
    else
        BASS_StreamFree(hndl);
}

void engine_equalizer_init(HSTREAM hndl, HFX &fx)
{
    fx = BASS_ChannelSetFX(hndl, BASS_FX_DX8_PARAMEQ, 1);
}

void engine_equalizer_setfreq(HFX& fx, WORD freq, int val)
{
    BASS_DX8_PARAMEQ PrEf;
    BASS_FXGetParameters(fx, &PrEf);
    PrEf.fGain = val;
    PrEf.fCenter = freq;
    BASS_FXSetParameters(fx, &PrEf);
}

/*ENGINE_PPLUGIN engine_plugin_getinfo(HPLUGIN plugin_hndl)
{
   return BASS_PluginGetInfo(plugin_hndl);
}*/
#define ARCH 64
#if ARCH == 32
    const char * pl_path = "/plugins/";
#elif ARCH == 64
    const char * pl_path = "/plugins64/";
#endif

void engine_load_plugin(char* fname)
{
    if (!BASS_PluginLoad(fname, 0 | BASS_UNICODE) && !BASS_PluginLoad(fname, 0))
    {
        fprintf(stderr, "PLUGINS %s could`nt be loaded ERRC == %d\n", fname, BASS_ErrorGetCode());
    }

    /*plugin_info = engine_plugin_getinfo(plugin_hndl);
    plg = *plugin_info;
    for (int i = 0; i < plg.formatc; i++)
    {
        filt_playable =  filt_playable + "|" + plg.formats[i].name + ' '
                + " (" + plg.formats[i].exts + "), " + fname + "|" +
                plg.formats[i].exts;
    }*/
}

static int check_fname(const char *fname)
{
    char * str = strdup(fname);
    char *first_part = strtok(str, "."), *second_part = strtok(NULL, "."), *third_part = strtok(NULL, ".");
    int res = (first_part != NULL && strstr(first_part, ENGINE_PLUGINSFILT) == first_part)
            && strcmp(first_part, ENGINE_PLUGINSFILT)
            && (second_part != NULL && !strcmp(second_part, ENGINE_PLUGINSEXT))
            && (third_part == NULL);
    free(str);
    return res;
}

void engine_load_all_plugins(void)
{
#ifndef _WIN32
    char *path = (char *)calloc(PATH_MAX + 1, sizeof(char));
    getcwd(path, PATH_MAX);
#ifndef X64
    strncat(path, pl_str, strlen(pl_str));
#else
    strncat(path, pl_str64, strlen(pl_str64));
#endif
    WORD rlen = strlen(path);

    DIR * d = opendir(path);
    struct dirent *dd;
    while ((dd = readdir(d)) != NULL)
    {
        struct stat st;
        strncat(path, dd->d_name, strlen(dd->d_name));
        if (!stat(path, &st) && S_ISREG(st.st_mode) && check_fname(dd->d_name)) {
            engine_load_plugin(path);
        }
        path[rlen] = 0;
    }
    free(path);
    closedir(d);
#endif
}

HSTREAM engine_channel_create(char* fname, bool faked)
{
    HSTREAM hndl;
    hndl = BASS_StreamCreateFile(0, (void *)fname, 0, 0, 0 or BASS_UNICODE);
    if ((!faked) && (hndl != 0))
        BASS_ChannelPlay(hndl, false);
    return hndl;
}

double engine_channel_bytes2seconds(HSTREAM hndl, QWORD pos)
{
    return BASS_ChannelBytes2Seconds(hndl, pos);
}

QWORD engine_channel_seconds2bytes(HSTREAM hndl, double pos)
{
    return BASS_ChannelSeconds2Bytes(hndl, pos);
}

float engine_channel_getlength(HSTREAM hndl)
{
    QWORD curlen;
    curlen = BASS_ChannelGetLength(hndl, BASS_POS_BYTE);
    return BASS_ChannelBytes2Seconds(hndl, curlen);
}

float engine_get_volume(HSTREAM hndl)
{
    return BASS_GetVolume();
}

float engine_get_cpu()
{
    return BASS_GetCPU();
}

float engine_get_attribute(HSTREAM hndl, DWORD params)
{
    float value;
    BASS_ChannelGetAttribute(hndl, params, &value);
    return value;
}














